<!DOCTYPE html>
<html>
  <head>
    <title>加密 HLS 播放器</title>
    <style>
      body {
        font-family: Arial, sans-serif;
        padding: 20px;
        max-width: 1000px;
        margin: 0 auto;
        background-color: #f5f5f5;
      }
      .container {
        background-color: white;
        padding: 20px;
        border-radius: 8px;
        box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
      }
      h1 {
        color: #333;
        border-bottom: 2px solid #eee;
        padding-bottom: 10px;
      }
      video {
        width: 100%;
        max-width: 800px;
        border-radius: 4px;
        margin: 20px 0;
      }
      button {
        background-color: #4caf50;
        border: none;
        color: white;
        padding: 10px 15px;
        text-align: center;
        text-decoration: none;
        display: inline-block;
        font-size: 14px;
        margin: 4px 8px 4px 0;
        cursor: pointer;
        border-radius: 4px;
        transition: background-color 0.3s;
      }
      button:hover {
        background-color: #45a049;
      }
      .status {
        margin: 15px 0;
        padding: 10px;
        background-color: #f0f0f0;
        border-radius: 4px;
        font-size: 14px;
      }
      .error {
        color: #d32f2f;
        background-color: #ffebee;
        padding: 10px;
        border-radius: 4px;
        margin: 10px 0;
        display: none;
      }
      .version {
        font-size: 12px;
        color: #666;
        margin-top: 5px;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <h1>加密 HLS 播放器</h1>
      <p>这个播放器演示了如何播放使用 AES-128 加密的 HLS 视频内容</p>
      <div class="version">HLS.js 版本: 1.1.5</div>

      <div class="controls">
        <button onclick="playVideo()">播放加密视频</button>
        <button onclick="playVideoWithKey()">指定密钥播放</button>
      </div>

      <div id="status" class="status">状态: 等待播放</div>
      <div id="error" class="error"></div>

      <video id="video" controls></video>
    </div>

    <!-- 使用特定版本的HLS.js，避免最新版可能存在的兼容性问题 -->
    <!-- <script src="https://cdn.jsdelivr.net/npm/hls.js@1.1.5"></script> -->
    <script src="/js/hls.js"></script>
    <script>
      const video = document.getElementById("video")
      const statusElement = document.getElementById("status")
      const errorElement = document.getElementById("error")
      let hls

      // 检查浏览器是否支持 HLS.js
      const isHlsSupported = Hls.isSupported()

      // 初始化 HLS 播放器
      function initPlayer() {
        if (hls) {
          hls.destroy()
          hls = null
        }

        if (isHlsSupported) {
          try {
            hls = new Hls({
              debug: true,
              enableWorker: false, // 禁用Web Worker可能有助于避免某些错误
              xhrSetup: function (xhr, url) {
                // 可以在这里添加请求拦截，例如添加认证信息
              }
            })

            // 设置HLS事件监听器
            setupHlsEvents()

            hls.attachMedia(video)
            return true
          } catch (error) {
            console.error("初始化HLS播放器失败:", error)
            showError(`初始化播放器失败: ${error.message}`)
            return false
          }
        } else {
          showError("您的浏览器不支持 HLS.js，请尝试使用 Safari 或其他支持 HLS 的浏览器")
          return false
        }
      }

      // 播放默认加密视频
      function playVideo() {
        clearError()
        const encryptedUrl = "/encrypted/input3/index.m3u8"
        updateStatus("正在加载加密视频...")

        if (initPlayer()) {
          if (isHlsSupported) {
            hls.loadSource(encryptedUrl)
          } else if (video.canPlayType("application/vnd.apple.mpegurl")) {
            video.src = encryptedUrl
            video.addEventListener("loadedmetadata", function () {
              video.play()
            })
          }
        }
      }

      // 播放带自定义密钥的加密视频
      function playVideoWithKey() {
        // 这里可以弹出一个输入框让用户输入密钥URL或上传密钥文件
        const keyUrl = prompt(
          "请输入密钥URL (如果不确定，请保持为空使用默认密钥):",
          "/encrypted/input3/encryption.key"
        )
        if (keyUrl === null) return // 用户取消

        clearError()
        const encryptedUrl = "/encrypted/input3/index.m3u8"
        updateStatus(`正在加载加密视频（使用自定义密钥: ${keyUrl}）...`)

        // 完全重置播放器
        if (hls) {
          hls.destroy()
          hls = null
        }
        console.log("🚀 - playVideoWithKey - hls:", hls)

        try {
          // 创建一个新的XMLHttpRequest来测试密钥是否可访问
          const xhr = new XMLHttpRequest()
          xhr.open("GET", keyUrl, true)
          xhr.responseType = "arraybuffer"

          xhr.onload = function () {
            if (xhr.status === 200) {
              updateStatus(`密钥文件验证成功，长度: ${xhr.response.byteLength} 字节`)

              // 密钥存在，继续初始化播放器
              initPlayerWithCustomKey(encryptedUrl, keyUrl, xhr.response)
            } else {
              showError(`密钥文件不存在或无法访问: ${xhr.status} ${xhr.statusText}`)
            }
          }

          xhr.onerror = function () {
            showError(`无法加载密钥文件: ${keyUrl}, 请检查URL是否正确`)
          }

          xhr.send()
        } catch (error) {
          console.error("初始化HLS播放器失败:", error)
          showError(`初始化播放器失败: ${error.message}`)
        }
      }

      // 使用自定义密钥初始化播放器
      function initPlayerWithCustomKey(videoUrl, keyUrl, keyData) {
        try {
          // 将密钥数据转换为Uint8Array
          const keyBytes = new Uint8Array(keyData)

          // 显示密钥数据的前几个字节(仅用于调试)
          const keyPreview = Array.from(keyBytes.slice(0, 4))
            .map(b => b.toString(16).padStart(2, "0"))
            .join("")
          console.log(`密钥预览: ${keyPreview}...`)

          // 创建播放器并配置 - 使用最简单的配置
          hls = new Hls({
            debug: false, // 关闭详细日志避免干扰
            enableWorker: false
          })

          // 设置常规事件监听器
          setupHlsEvents()

          // 添加更直接的方法来处理密钥
          // 方法1：替换key-loader.js的加载处理
          let keyLoadCount = 0

          // 监听密钥加载并替换
          hls.on(Hls.Events.KEY_LOADING, function (event, data) {
            keyLoadCount++
            console.log(`密钥加载请求 #${keyLoadCount}:`, data.frag.decryptdata.uri)
            updateStatus(`检测到密钥请求 #${keyLoadCount}: ${data.frag.decryptdata.uri}`)

            // 尝试直接替换密钥
            setTimeout(() => {
              try {
                // 直接设置密钥数据
                if (data.frag && data.frag.decryptdata) {
                  console.log("直接设置密钥数据")
                  data.frag.decryptdata.key = keyBytes

                  // 触发密钥加载完成事件
                  hls.trigger(Hls.Events.KEY_LOADED, {
                    frag: data.frag
                  })
                }
              } catch (err) {
                console.error("替换密钥出错:", err)
              }
            }, 10)
          })

          // 附加媒体元素
          hls.attachMedia(video)

          // 加载视频源
          hls.loadSource(videoUrl)
        } catch (error) {
          console.error("使用自定义密钥初始化播放器失败:", error)
          showError(`初始化播放器失败: ${error.message}`)
        }
      }

      // 自定义密钥加载器 (备用方法)
      function customKeyLoader(keyUrl) {
        const OriginalLoader = Hls.DefaultConfig.loader

        class CustomLoader extends OriginalLoader {
          constructor(config) {
            super(config)
            this.keyUrl = keyUrl
          }

          load(context, config, callbacks) {
            if (context.type === "key") {
              const originalUrl = context.url
              context.url = this.keyUrl
              updateStatus(`使用自定义密钥: ${this.keyUrl}`)
            }
            super.load(context, config, callbacks)
          }
        }

        return CustomLoader
      }

      // 设置HLS事件监听器
      function setupHlsEvents() {
        // 监听错误
        hls.on(Hls.Events.ERROR, function (event, data) {
          console.error("HLS错误:", data)

          if (data.fatal) {
            switch (data.type) {
              case Hls.ErrorTypes.NETWORK_ERROR:
                showError(`网络错误，尝试恢复... 详情: ${data.details}`)
                hls.startLoad()
                break
              case Hls.ErrorTypes.MEDIA_ERROR:
                showError(`媒体错误，尝试恢复... 详情: ${data.details}`)
                hls.recoverMediaError()
                break
              default:
                showError(
                  `无法恢复的错误: ${data.details}, 原因: ${
                    data.error ? data.error.message : "未知"
                  }`
                )
                break
            }
          } else {
            console.warn("非致命错误:", data)
            updateStatus(`处理非致命错误: ${data.details}`)
          }
        })

        hls.on(Hls.Events.MANIFEST_PARSED, function () {
          updateStatus("视频已加载，准备播放")
          video.play().catch(e => {
            updateStatus("自动播放失败，请点击视频播放")
            console.warn("自动播放被阻止:", e)
          })
        })

        hls.on(Hls.Events.KEY_LOADING, function (event, data) {
          updateStatus("正在加载解密密钥...")
          console.log("密钥加载中:", data)
        })

        hls.on(Hls.Events.KEY_LOADED, function (event, data) {
          updateStatus("解密密钥已加载")
          console.log("密钥已加载:", data)
        })

        // 添加更多调试信息
        hls.on(Hls.Events.FRAG_LOADING, function () {
          updateStatus("正在加载视频片段...")
        })

        hls.on(Hls.Events.FRAG_LOADED, function () {
          updateStatus("视频片段已加载")
        })
      }

      // 更新状态显示
      function updateStatus(message) {
        statusElement.textContent = "状态: " + message
        console.log("状态更新:", message)
      }

      // 显示错误
      function showError(message) {
        errorElement.textContent = "错误: " + message
        errorElement.style.display = "block"
        console.error("显示错误:", message)
      }

      // 清除错误
      function clearError() {
        errorElement.textContent = ""
        errorElement.style.display = "none"
      }
    </script>
  </body>
</html>
